package org.swift.mashup.engine.concurrency.agenda;

import org.apache.log4j.Logger;
import org.swift.mashup.engine.concurrency.ConcurrentContext;
import org.swift.mashup.engine.concurrency.LocalConcurrentContext;
import org.swift.mashup.engine.concurrency.StaticConcurrentConfiguration;
import org.swift.mashup.engine.concurrency.execution.Reasoner;
import org.swift.mashup.engine.concurrency.execution.RuleSet;
import org.swift.mashup.engine.concurrency.memory.WorkingMemory;

import edu.emory.mathcs.backport.java.util.Collections;

public class JobSet implements Runnable {
	private final String processId;
	private final String sessionId;
	private final String workingDirectory;
	private final int limit;
	private final int newMemoryPosition;	
	
	// TODO change the RuleSet to be mashup name and provide as part of mashup
	// execution
	protected final RuleSet ruleSet;
	/**
	 * computeNode for this class is kinda useless, but we'll hold it and print it just for giggles.
	 * 
	 * It is used in subclasses
	 */
	private String computeNode;
	private String url = null;
	private ConcurrentContext context = null;
	
	/**
	 * Holds ref to any error that may have occurred executing the job.
	 */
	private Exception error = null;
	protected int executionAttempts = 0;
	
	private final static Logger log = Logger.getLogger(JobSet.class);

	public JobSet(String processId, String sessionId, String workingDirectory,
			int startindex, int endindex, RuleSet ruleSet) {
		this.processId = processId;
		this.sessionId = sessionId;
		this.workingDirectory = workingDirectory;
		this.newMemoryPosition = startindex;
		this.limit = endindex;
		this.ruleSet = ruleSet;
	}
	
	public JobSet(ConcurrentContext context, String url, String processId,
			String workingDirectory, int startindex, int endindex, 
			RuleSet ruleSet) {
		this.context = context;
		this.context = context;
		this.processId = processId;
		this.url = url;
		this.sessionId = context.getSessionID();
		this.workingDirectory = workingDirectory;
		this.newMemoryPosition = startindex;
		this.limit = endindex;
		this.ruleSet = ruleSet;
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer("Process ID = ");
		buf.append(this.processId);
		buf.append(",Session = ");
		buf.append(this.sessionId);
		buf.append(",Memory Item Range = ");
		buf.append(this.newMemoryPosition);
		buf.append(" - ");
		buf.append(this.limit);
		return buf.toString();
	}

	@SuppressWarnings("unchecked")
	@Override
	public void run() {
		log.debug("Running with local jobset on node: " + this.computeNode);
		LocalConcurrentContext context = new LocalConcurrentContext(this.sessionId, 
				new StaticConcurrentConfiguration(Collections.singletonList(this.processId),workingDirectory), 
				this.ruleSet);
		WorkingMemory memory = new WorkingMemory(ruleSet.getMemoryTypes(),
				context.getWorkingDirectory() + "/workingMemory", context
						.getSessionID(), this.processId, this.limit,
				this.newMemoryPosition);
		Reasoner reasoner = new Reasoner(this.ruleSet, memory, context);
		reasoner.fireConcurrent();
		memory.destroyMemoryFiles();
		executionAttempts++;
	}

	protected String getProcessId() {
		return processId;
	}

	protected String getSessionId() {
		return sessionId;
	}

	protected String getWorkingDirectory() {
		return workingDirectory;
	}

	protected int getLimit() {
		return limit;
	}

	protected int getNewMemoryPosition() {
		return newMemoryPosition;
	}

	protected RuleSet getRuleSet() {
		return ruleSet;
	}
	
	public String getComputeNode() {
		return this.computeNode;
	}
	
	public void setComputeNode (String computeNode){
		this.computeNode = computeNode;
	}
	
	public void clearErrors (){
		this.error = null;
	}

	public Exception getError() {
		return error;
	}
	
	protected void setError (Exception error){
		this.error = error;
	}

	public int getExecutionAttempts() {
		return executionAttempts;
	}
	
	public ConcurrentContext getContext () {
		return this.context;
	}
	
	public String getUrl() {
		return url;
	}
}
